Skip to content

gh-149835: Resolve symlinks in shutil._destinsrc#149851

Closed
ding-alex wants to merge 1 commit into
python:mainfrom
ding-alex:ding-alex/gh-149835-destinsrc-realpath
Closed

gh-149835: Resolve symlinks in shutil._destinsrc#149851
ding-alex wants to merge 1 commit into
python:mainfrom
ding-alex:ding-alex/gh-149835-destinsrc-realpath

Conversation

@ding-alex
Copy link
Copy Markdown

@ding-alex ding-alex commented May 14, 2026

Fixes #149835.

shutil.move, in the cross-device fallback path, uses _destinsrc(src, dst) to refuse moving a directory into itself (which would make copytree recurse infinitely). The guard normalises the two paths with os.path.abspath and then does a string-prefix check. abspath only collapses . / .. components — it does not resolve symlinks — so a symlink component anywhere in dst can make a destination that is physically inside src look like it is outside in string space, and the guard silently passes.

This change uses os.path.realpath for both src and dst so the comparison is done on the resolved, canonical paths.

A regression test (TestMove.test_destinsrc_symlink_bypass) is added that constructs the symlink layout described in the issue and asserts that _destinsrc correctly reports containment.

Author: @ding-alex


Pull Request opened by Augment Code | View session

Use os.path.realpath instead of os.path.abspath when normalising the
src and dst paths in shutil._destinsrc. abspath only collapses '.' and
'..' components, so a symlink anywhere in dst could let a destination
that is physically inside src appear to be outside it in string space,
silently bypassing the cross-device move guard in shutil.move and
causing copytree to recurse infinitely.

Add a regression test that constructs such a symlink and asserts
_destinsrc still detects the containment.
@python-cla-bot
Copy link
Copy Markdown

The following commit authors need to sign the Contributor License Agreement:

CLA not signed

@ding-alex
Copy link
Copy Markdown
Author

PR Author Agent⚡ on behalf of @ding-alex

👋 I'm driving this PR from here to merge. Here's what I'll do:

  • Respond to review feedback — I'll implement suggestions, answer questions, and fix issues raised by reviewers
  • Fix CI failures — I receive real-time notifications when checks fail and will attempt to fix them automatically
  • Resolve merge conflicts — if the PR falls behind the base branch, I'll bring it up to date
  • Assign reviewers — once the PR is ready for review, I'll find the right reviewers and request their review
  • Drive to merge — I'll track all gates (CI, reviews, verification) and notify the PR owner when it's ready

I'll post updates here as the PR progresses. Feel free to leave a comment anytime!

Note: this PR was opened as a draft — @ding-alex, please mark it ready-for-review when you'd like reviewers requested.

@ding-alex ding-alex closed this May 14, 2026
@ding-alex
Copy link
Copy Markdown
Author

PR Author Agent⚡ on behalf of @ding-alex

@ding-alex PR is blocked by CLA signing. Please sign the Python Software Foundation CLA at https://cla.python.org/ — I can't resolve this from the agent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

shutil.move can move the dir into itself (with a symlink)

1 participant